#include <qlmdb/database.h>

#include "datamodel/item.h"
#include "datamodel/library.h"
#include "datastorage/itemsquery.h"


/**
 * @brief Constructor.
 */
ItemsQuery::ItemsQuery(QObject *parent) : QObject(parent),
    m_context(),
    m_global(),
    m_items(),
    m_children(),
    m_dataChanged(false),
    m_changedLibrariesUids(),
    m_changedParentUids()
{
}


/**
 * @brief Destructor.
 */
ItemsQuery::~ItemsQuery()
{
}


/**
 * @brief The database containing global settings.
 */
QSharedPointer<QLMDB::Database> ItemsQuery::global() const
{
    return m_global;
}


/**
 * @brief The database containing item data.
 */
QSharedPointer<QLMDB::Database> ItemsQuery::items() const
{
    return m_items;
}


/**
 * @brief The database containing parent/child relationships.
 */
QSharedPointer<QLMDB::Database> ItemsQuery::children() const
{
    return m_children;
}


/**
 * @brief Indicate that the query changed the cache contents.
 *
 * This method shall be called by concrete sub-classes to indicate that the
 * cache contents have been changed.
 * @param changed
 */
void ItemsQuery::setDataChanged(bool changed)
{
    m_dataChanged = changed;
}


/**
 * @brief Returns true if the query has changed the cache.
 *
 * @sa setDataChanged()
 */
bool ItemsQuery::hasDataChanged() const
{
    return m_dataChanged;
}


/**
 * @brief Mark an item as changed.
 *
 * This marks the item with the given @p id as changed. This will cause the
 * librariesChanged() signal to be emitted when the transaction is done.
 */
void ItemsQuery::markAsChanged(QLMDB::Transaction &transaction, QByteArray id)
{
    while (!m_changedParentUids.contains(id)) {
        auto entry = m_items->get(transaction, id);
        if (!entry.isEmpty()) {
            auto itemEntry = ItemCacheEntry::fromByteArray(entry, id);
            if (itemEntry.valid) {
                m_changedParentUids.insert(id);
                id = itemEntry.parentId.toByteArray();
            } else {
                auto libEntry = LibraryCacheEntry::fromByteArray(entry, id);
                if (libEntry.valid) {
                    m_changedLibrariesUids.insert(id);
                    m_changedParentUids.insert(id);
                    setDataChanged(true);
                    break;
                }
            }
        } else {
            break;
        }
    }
}


/**
 * @brief The context of the cache data base.
 */
QSharedPointer<QLMDB::Context> ItemsQuery::context() const
{
    return m_context;
}


/**
 * @brief Indicate that the query is done.
 *
 * This method shall be called by sub-classes of the ItemsQuery class.
 * It will cause the finished() signal to be emitted, which other classes
 * should use to get informed that the query has been processed.
 */
void ItemsQuery::finish()
{
    if (m_dataChanged) {
        emit dataChanged();
    }
    if (!m_changedLibrariesUids.isEmpty()) {
        QVariantList librariesUids;
        for (auto id : m_changedLibrariesUids) {
            librariesUids << QUuid(id);
        }
        emit librariesChanged(librariesUids);
    }
    emit finished();
}
